﻿#pragma once

#include <list>
#include <fmt/format.h>

#include <breaking/log/log_event.h>
#include <breaking/base/singleton.h>
#include <breaking/log/log_appender.h>
#include <breaking/time/time.h>

namespace breaking
{
	/**
	 * @brief 日志类
	 */
	class logger : public singleton<logger>
	{
	public:
		logger();
		~logger();

		/**
		 * @brief 添加 appender
		 * @param appender
		 */
		bool add_appender(log_appender* appender);

		/**
		 * @brief 设置日志优先级
		 */
		void set_priority(log_priority priority);

		/**
		 * @brief 是否可以输出日志
		 * @param priority
		 * @return
		 */
		bool is_loggable(log_priority priority);

		/**
		 * @brief 输出日志, 支持fmt格式化
		 * @tparam ...Args
		 * @param priority
		 * @param format
		 * @param ...args
		 */
		template <typename... Args>
		void log_format(log_priority priority, const char* format_str, const Args& ... args)
		{
			if (!is_loggable(priority)) return;

			log_event event;
			event.priority = priority;
			event.log_time = breaking::time::current_time();
			try
			{
				auto va = fmt::make_format_args(args...);
				auto buffer = fmt::memory_buffer();
				vformat_to(fmt::appender(buffer), format_str, va);
				event.message = to_string(buffer);
			}
			catch (const fmt::format_error& e)
			{
				event.priority = log_priority::LOG_ERROR;
				event.message = fmt::format("message({}) formatting error: {}", format_str, e.what());
			}

			add_log_event(event);
		}

		/**
		 * @brief 输出日志, 支持fmt格式化, 带文件名, 函数名, 行号
		 * @tparam ...Args
		 * @param priority
		 * @param file
		 * @param func
		 * @param line
		 * @param format_str
		 * @param ...args
		 */
		template <typename... Args>
		void log_format(log_priority priority, const char* file, const char* func, int32_t line, const char* format_str, const Args& ... args)
		{
			if (!is_loggable(priority)) return;

			log_event event;
			event.priority = priority;
			event.log_time = breaking::time::current_time();
			try
			{
				auto va = fmt::make_format_args(args...);
				auto buffer = fmt::memory_buffer();
				vformat_to(fmt::appender(buffer), format_str, va);
				event.message = to_string(buffer);
			}
			catch (const fmt::format_error& e)
			{
				event.priority = log_priority::LOG_ERROR;
				event.message = fmt::format("message({}) formatting error: {}", format_str, e.what());
			}

			event.message = fmt::format("[{}] [{}] [{}] {}", file, func, line, event.message);

			add_log_event(event);
		}

		/**
		 * @brief 添加日志事件
		 * @param priority
		 * @param event
		 */
		void add_log_event(const log_event& event);

	private:
		// 输出日志的优先级
		log_priority				m_priority;
		// appender 列表
		std::list<log_appender*>	m_appenders;
		// appender 的锁
		std::mutex					m_mutex;
	};
}